package model;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.net.SocketTimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Douglas
 */
public class Carro extends Thread {

    private int[] rota;// 1º Rec, 2º Rec, 3º Rec, Nº Pista
    private int time = 0;
    private int ID;
    private boolean ler = true;
    private boolean ler2 = true;
    private MulticastSocket socket;
    private InetAddress grupo;
    private int porta;
    private boolean atravessou;
    private boolean token;
    private int[] depend = {0, 0, 0, 0};

    //     _  2  _
    //      |C|B|
    //  3  _|D|A|_  1
    //        4
    public Carro(int[] rota) throws IOException {
        this.rota = rota;
        ///CalcTemp(rota);
        grupo = InetAddress.getByName("225.4.5.6");
        porta = 44444;
        atravessou = false;
        token = false;
        ID = -1;
    }

    public void CalcTemp(int[] vector) {

        for (int j = 1; j < 4; j++) {
            if (vector[j] != 0) {
                time = time + 2;
            }
        }
    }

    public int getID() {
        return ID;
    }

    public void decrementID() {
        ID--;
    }

    public synchronized void setAtravessou() {
        while (ler) {
            try {
                wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        //ler = false;
        atravessou = true;
        token = false;
        ler = true;
        //notify();
    }

    public synchronized boolean getAtravessou() {
        ler = true;
        boolean temp = atravessou;
        ler = false;
        notify();
        return temp;
    }

    public synchronized void setTime(int timeDec, int recLib) {
        while (ler2) {
            try {
                wait();
            } catch (InterruptedException ex) {
                Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        time = time - timeDec;
        if (recLib != -1) {
            rota[recLib] = 0;
        }
        ler2 = true;
        //notify();
    }

    public synchronized int getTime() {
        ler2 = true;
        int temp = time;
        ler2 = false;
        notify();
        return temp;
    }

    @Override
    public void run() {
        System.out.println("ENTROU");
        try {
            socket = new MulticastSocket(porta);
        } catch (IOException ex) {
            Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("ERRO AO ENTRAR NO GRUPO OU AO CRIAR O SOCKET");
            socket.close();
            this.interrupt();
        }

        sendMsg("HI:" + rota[0] + ":" + rota[1] + ":" + rota[2] + ":" + rota[3], 0);

        String msg;

        while (true) {
            if ((!token)) {
                msg = receiveMsg(socket, 100);
            } else {
                msg = receiveMsg(socket, getTime());
            }
            //usar indices para os diferentes timeouts
            // hi = false;
            switch (msg.split(":")[0]) {

                case "HI":
                    calcDepend(msg.substring(3));
                    if ((depend[0] != 0) || (depend[1] != 0) || (depend[2] != 0) || (depend[3] != 0)) {
                        sendMsg("HCC:" + depend[0] + ":" + depend[1] + ":" + depend[2] + ":" + depend[3], 0);
                    }
                    break;

                case "HCC":
                    int[] vector = {Integer.parseInt(msg.split(":")[1]), Integer.parseInt(msg.split(":")[2]),
                        Integer.parseInt(msg.split(":")[3]), Integer.parseInt(msg.split(":")[4])};
                    CalcTemp(vector);


                    break;

                case "EXP":
                    //RESERVAR OS RECURSOS AQUI (atravessar o cruzamento)
                    token = true;
                    CalcTemp(rota);
                    new ThreadTimer(time, this).start();
                    System.out.println("ATRAVESSANDO O CRUZAMENTO");
                    try {

                        socket.leaveGroup(InetAddress.getByName("225.4.5.6"));
                    } catch (IOException ex) {
                        Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    socket.close();
                    //atravessou = true;
                    break;
            }
        }
    }

    public void calcDepend(String msg) {

        int aux;
        for (int i = 0; i < 4; i++) {
            aux = Integer.parseInt(msg.split(":")[i]);
            if (aux != 0) {
                depend[1] = 1;
            }
        }
    }

    public void sendMsg(String msg, int random) {
        byte buf[] = msg.getBytes();

        //Criando pacote a ser enviado
        DatagramPacket pack = new DatagramPacket(buf, buf.length, grupo, porta);
        try {
            socket.leaveGroup(grupo);
            if (random == 1) {
                this.sleep((int) Math.random() * 100);
            }
            socket.send(pack);

        } catch (InterruptedException ex) {
            Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                socket.joinGroup(grupo);
            } catch (IOException ex) {
                Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
                System.out.println("ERRO AO ENTRAR NO GRUPO");
            }
        }
        System.out.println("ENVIOU");
    }

    public String receiveMsg(MulticastSocket socket, int timeout) {
        //criando pacote para receber informações pelo socket UDP            
        byte buf[] = new byte[1024];
        DatagramPacket pack = new DatagramPacket(buf, buf.length);
        //seta timeout

        try {
            socket.setSoTimeout(timeout);
            System.out.println(socket.getSoTimeout());
            socket.receive(pack);
        } catch (SocketTimeoutException ex) {
            System.out.println("expirou");
            return "EXP:";
        } catch (IOException ex) {
            Logger.getLogger(Carro.class.getName()).log(Level.SEVERE, null, ex);
        }

        return pack.getData().toString();
    }

    public static void main(String[] args) throws IOException {
        //int[] rota = {1, 1, 0, 0};
        //new Carro(rota);
        int i = 0;
        do {
            System.out.println(i);
            i++;
        } while (i < 3);
    }
}
